package javaAdvanced;

import java.io.IOException;
import java.io.PrintWriter;

/**
 * 类加载器学习
 *
 * @author cuiH
 * Date: 13-12-6
 */
public class ClassLoaderTest {
    public static void main(String[] args) {
        System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
        /**
         * result:sun.misc.Launcher$AppClassLoader
         * AppClassLoader 加载的
         */


        System.out.println(System.class.getClassLoader());
        /**
         * result:null
         * 加载器为null，说明是由bootstrap加载器进行加载的
         */


        ClassLoader loader = ClassLoaderTest.class.getClassLoader();
        while (loader != null) {
            System.out.println(loader.getClass().getName());
            loader = loader.getParent();
        }
        System.out.println(loader);
        /**
         * result:
         * sun.misc.Launcher$AppClassLoader [加载classPath各种jar包下面类]
         * sun.misc.Launcher$ExtClassLoader [加载 Ext下面的各种jar包]
         * null（Bootstrap）[加载rt.jar]
         * 说明三个类加载器的父子关系
         */
    }

    /**
     * web项目中的一个类加载器的测试（Tomcat中servlet DoGet方法的加载器）
     * org.apache.catalina.loader.WebappClassLoader
     * org.apache.catalina.loader.StandardClassLoader
     * sun.misc.Launcher$AppClassLoader
     * sun.misc.Launcher$ExtClassLoader
     *
     * 两个apache 两个java
     * 这个放到web项目下好用。
     */
    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        ClassLoader loader = this.getClass().getClassLoader();
        while (loader != null) {
            out.println(loader.getClass().getName() + "</br>");
            loader = loader.getParent();
        }
        out.close();
    }

}

/**
 * jvm默认三个类加载器
 * 类加载器本质也是一个类
 * java虚拟机第一个加载器是BootStrap，加载其他类加载器，然后加载类
 *
 * 默认的三个BootStrap ;AppClassLoader;ExtClassLoader
 *
 * 类加载器的委托方式：
 * 加载方式：首先向上委托，，追寻到Bootstrap，上面有的话，直接加载，没有的话向下寻找。
 * 因此自己写的System类无法被加载，因为找到最上面，就直接加载system类了
 */


/**
 * 编写字节的类加载器
 * 模板方法的设计模式
 *
 * 父类里有loaderClass方法
 *
 * 子类1（自己的代码）
 * 子类2（自己的代码）
 *
 * 子类1和子类2的流程一样，但是具体实现方法不一样。
 * 因此，将实现流程的代码写在父类中，具体的实现代码由子类实现
 * 例如JDK中，ClassLoader.loaderClass使用的就是模板方法
 *
 * ClassLoader.loaderClass方法包括三步流程：
 * 一：findLoaderClass（）检查是否加载
 * 二：父类加载器中调用 loaderClass方法
 * 三: findClass查找类。
 *
 * 因此：要想写一个自己的类加载器，只需要覆盖findClass便可以实现
 */
